/**
 * Copyright 2014 wasu.com
 *
 *
 * Create on 2015-7-5 下午11:08:16
 */
package xiaojian.toolkit.handler;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.management.ObjectName;

import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jmx.export.MBeanExporter;

import com.google.common.base.Preconditions;

/**
 * @author <a href="mailto:caoxiaojian@wasu.com>xiaojian.cao</a>
 * 
 */
public abstract class AbstractReqHandler<Q extends AbstractRequest> implements
		ReqHandler<AbstractRequest>, BeanNameAware {

	private static final Logger logger = LoggerFactory
			.getLogger(AbstractReqHandler.class);

	// JMX support
	@Autowired
	@Qualifier("serviceExporter")
	private volatile MBeanExporter mbeanExporter = null;

	private String beanName;

	protected AtomicInteger completedCount = new AtomicInteger(0);

	/**
	 * 因为服务器忙被忽略的请求。
	 */
	protected AtomicInteger busyIgnoredCount = new AtomicInteger(0);

	// -- 当前活动的任务
	private final AtomicInteger activeJobCount = new AtomicInteger(0);

	// -- 此handler最大允许同时处理的任务数。
	@Value("${handler.busyThreshold:200}")
	private volatile int busyThreshold = 200;

	protected HandlerDashboard dashboard = new HandlerDashboardImpl();

	protected volatile long dealLargestTTA = -1;
	protected volatile long dealSmallestTTA = -1;
	private final AtomicLong dealTotalTTA = new AtomicLong(0);

	private ObjectName dashboardObjectName = null;

	public void setBeanName(String name) {
		this.beanName = name;
	}

	public int getBusyThreshold() {
		return busyThreshold;
	}

	public void setBusyThreshold(int busyThreshold) {
		this.busyThreshold = busyThreshold;
	}

	/**
	 * 子类必须实现该方法。
	 * 
	 * @param request
	 */
	public abstract void doReq0(Q request);

	/**
	 * 处理服务器忙，默认方法为空方法。不做任何处理。
	 * 
	 * @param request
	 */
	protected void doBusy(AbstractRequest request) {

	}

	@Override
	@SuppressWarnings("unchecked")
	public void doReq(AbstractRequest request) {
		Preconditions.checkArgument(request != null
				&& request.getIdentification() != null);

		if (activeJobCount.get() >= busyThreshold) {
			logger.warn("Process request[{}] fail, server busy.", request);

			doBusy(request);
			busyIgnoredCount.incrementAndGet();
			return;
		}

		activeJobCount.incrementAndGet();
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		doReq0((Q) request);
		stopWatch.stop();
		activeJobCount.decrementAndGet();

		long escapeTime = stopWatch.getTime();

		dealTotalTTA.addAndGet(escapeTime);
		completedCount.incrementAndGet();

		if (escapeTime > this.dealLargestTTA) {
			this.dealLargestTTA = escapeTime;
		}

		if (escapeTime < this.dealSmallestTTA) {
			this.dealSmallestTTA = escapeTime;
		}

	}

	@PostConstruct
	public void start() {
		final MBeanExporter exporter = mbeanExporter;

		if (null != exporter) {
			try {
				dashboardObjectName = new ObjectName(
						"prefix:class=handler,name=" + beanName
								+ ",module=dashboard");
				exporter.registerManagedResource(dashboard, dashboardObjectName);
			} catch (Exception e) {
				logger.error("registerMBean", e);
			}
		}
	}

	@PreDestroy
	public void stop() {
		if (dashboard != null) {
			mbeanExporter.unregisterManagedResource(dashboardObjectName);
		}
	}

	public class HandlerDashboardImpl implements HandlerDashboard {

		/**
		 * @see xiaojian.toolkit.handler.HandlerDashboard#getDealLargestTTA()
		 */
		@Override
		public long getDealLargestTTA() {
			return dealLargestTTA;
		}

		/**
		 * @see xiaojian.toolkit.handler.HandlerDashboard#getDealSmallestTTA()
		 */
		@Override
		public long getDealSmallestTTA() {
			return dealSmallestTTA;
		}

		/**
		 * @see xiaojian.toolkit.handler.HandlerDashboard#getDealCompletedCount()
		 */
		@Override
		public long getDealCompletedCount() {
			return completedCount.get();
		}

		/**
		 * @see xiaojian.toolkit.handler.HandlerDashboard#getDealAverageTTA()
		 */
		@Override
		public long getDealAverageTTA() {
			int completed = completedCount.get();
			return completed > 0 ? dealTotalTTA.get() / completed : -1;
		}

		@Override
		public int getActiveJobCount() {
			return activeJobCount.get();
		}

		@Override
		public int getBusyThreshold() {
			return busyThreshold;
		}

		@Override
		public void setBusyThreshold(int busyThreshold) {
			AbstractReqHandler.this.setBusyThreshold(busyThreshold);
		}

		@Override
		public int getBusyIgnoredCount() {
			return busyIgnoredCount.get();
		}

	}

}
